package group.raber.saber.lang;

import group.raber.saber.kit.DateKit;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 封装之后的值对象,方便进行做任意转换
 */
public class ValueObject {
    private Object value;
    private ValueType type;
    private static Pattern NUMBER_PATTERN = Pattern.compile("^(\\-|\\+)?\\d+(\\.\\d+)?$");
    private static DecimalFormat NUMBER_FORMAT = new DecimalFormat("#.################################");

    public enum ValueType {
        String, Boolean, Number, Date, Object, Null,Array
    }

    public ValueType getValueType() {
        return type;
    }

    public static ValueObject valueOf(Object value) {
        return new ValueObject(value);
    }

    public ValueObject(Object value) {
        if(value instanceof ValueObject){
            value = ((ValueObject)value).value();
        }
        if (value == null) {
            this.type = ValueType.Null;
        } else if (value instanceof String) {
            this.type = ValueType.String;
        } else if (value instanceof Number) {
            this.type = ValueType.Number;
        } else if (value instanceof Date) {
            this.type = ValueType.Date;
        } else if(value.getClass().isArray()) {
            this.type = ValueType.Array;
        } else {
            this.type = ValueType.Object;
        }
        this.value = value;
    }

    public Object value() {
        return this.value;
    }

    @SuppressWarnings("unchecked")
    public <T> T objectVal(Class<T> classType) {
        return (T) value;
    }

    public Number numberValue() {
        if (type == ValueType.Number) {
            return (Number) value;
        } else if (type == ValueType.String && NUMBER_PATTERN.matcher((String) value).matches()) {
            return Double.parseDouble((String) value);
        } else {
            throw new RuntimeException("value [" + value + "] is not a digital format");
        }
    }

    public Long longValue() {
        return numberValue().longValue();
    }

    public Integer intValue() {
        return numberValue().intValue();
    }

    public Double doubleValue() {
        return numberValue().doubleValue();
    }

    public String strValue() {
        return strValue(null);
    }
    public String strValue(String nullDefault) {
        if (type == ValueType.Number) {
            return NUMBER_FORMAT.format(numberValue());
        } else if (type == ValueType.String) {
            return (String) value;
        } else if (type == ValueType.Date) {
            return (new SimpleDateFormat(DateKit.DATE_TIME_FORMAT)).format(dateValue());
        } else if (type == ValueType.Null) {
            return nullDefault;
        } else {
            return value.toString();
        }
    }

    public Date dateValue() {
        if (type == ValueType.Number) {
            return DateKit.parse(longValue());
        } else if (type == ValueType.String) {
            return DateKit.parse(strValue());
        } else if (type == ValueType.Date) {
            return (Date) value;
        } else if (type == ValueType.Null) {
            return null;
        } else {
            throw new RuntimeException("value [" + value + "] is not a date format");
        }
    }

    public Boolean boolValue() {
        if (type == ValueType.String) {
            return Boolean.parseBoolean(strValue());
        } else if (type == ValueType.Boolean) {
            return (Boolean) value;
        } else if (type == ValueType.Null) {
            return null;
        } else {
            throw new RuntimeException("value [" + value + "] is not a boolean format");
        }
    }

    public Object[] objectArray(){
        Object[] values = null;
        if(value==null)return values;
        if(value.getClass().isArray()){
            return (Object[])value;
        }else if(value instanceof List){
            @SuppressWarnings("rawtypes")
            List<?> vList = (List)value;
            values = new Object[vList.size()];
            for(int i=0;i<vList.size();i++){
                values[i] = vList.get(i);
            }
        }
        return values;
    }

    public Number[] numberArray(){
        Object[] values = objectArray();
        if(values==null||values.length==0)return null;
        Number[] ret = new Number[values.length];
        for(int i=0;i<values.length;i++){
            ValueObject vo = new ValueObject(values[i]);
            ret[i] = vo.numberValue();
        }
        return ret;
    }

    public Long[] longArray() {
        Number[] numbers = numberArray();
        Long[] ret = new Long[numbers.length];
        for(int i=0;i<numbers.length;i++){
            ret[i] = numbers[i].longValue();
        }
        return ret;
    }

    public Integer[] intArray() {
        Number[] numbers = numberArray();
        Integer[] ret = new Integer[numbers.length];
        for(int i=0;i<numbers.length;i++){
            ret[i] = numbers[i].intValue();
        }
        return ret;
    }

    public Double[] doubleArray() {
        Number[] numbers = numberArray();
        Double[] ret = new Double[numbers.length];
        for(int i=0;i<numbers.length;i++){
            ret[i] = numbers[i].doubleValue();
        }
        return ret;
    }

    public String[] strArray() {
        Object[] values = objectArray();
        if(values==null||values.length==0)return null;
        String[] ret = new String[values.length];
        for(int i=0;i<values.length;i++){
            ValueObject vo = new ValueObject(values[i]);
            ret[i] = vo.strValue();
        }
        return ret;
    }

    public Date[] dateArray() {
        Object[] values = objectArray();
        if(values==null||values.length==0)return null;
        Date[] ret = new Date[values.length];
        for(int i=0;i<values.length;i++){
            ValueObject vo = new ValueObject(values[i]);
            ret[i] = vo.dateValue();
        }
        return ret;
    }

    public Boolean[] boolArray() {
        Object[] values = objectArray();
        if(values==null||values.length==0)return null;
        Boolean[] ret = new Boolean[values.length];
        for(int i=0;i<values.length;i++){
            ValueObject vo = new ValueObject(values[i]);
            ret[i] = vo.boolValue();
        }
        return ret;
    }

    /**
     * 值是否为NULL
     *
     * @return
     */
    public boolean isNull() {
        return value == null;
    }

    /**
     * 值对象是否为没有内容,例如空字串,空集合等情况
     *
     * @return
     */
    @SuppressWarnings("rawtypes")
    public boolean isEmpty() {
        if (isNull()) return true;
        if (value.getClass().isArray()) {
            return ((Object[]) value).length == 0;
        } else if (value instanceof Collection) {
            return ((Collection) value).size() == 0;
        }
        return false;
    }

    public boolean isArray(){
        if(value==null)return false;
        return value.getClass().isArray();
    }

    public String toString() {
        if(isArray()){
            StringBuffer stringBuffer = new StringBuffer("{");
            Object[] values = objectArray();
            for(int i=0;i<values.length;i++){
                stringBuffer.append(values[i]).append(",");
            }
            if(stringBuffer.charAt(stringBuffer.length()-1) == ','){
                stringBuffer.deleteCharAt(stringBuffer.length()-1);
            }
            stringBuffer.append("}");
            return stringBuffer.toString();
        }else{
            if (value != null) {
                return strValue();
            } else {
                return null;
            }
        }
    }
}